#include "Tack.hpp"

#define MAX 3

Task task;

class EndPoint
{
private:
  static int num;
public:
  string namestr;
  int write_fd;
  pid_t child_fd;
public:
  EndPoint(int writefd,pid_t childfd)
    :write_fd(writefd)
    ,child_fd(childfd)
  {
    char buffer[1024];
    snprintf(buffer,sizeof(buffer),"process->%d[write_fd:%d:child_fd:%d]",num++,write_fd,child_fd);
    namestr = buffer;
  }
  const string GetName() const
  {
    return namestr;
  }
};

int EndPoint::num = 0;

void waitCommant()
{
  while(true)
  {
    int command = 0;
    int n = read(0,&command,sizeof(int));
    if(n == 0)
    {      
      cout << "父进程要我退出了 " << getpid() << endl;
      break;
    }
    else if(n == sizeof(int))
    {
      task.Excute(command);
    }
    else
    {
      break;
    }
  }
}

int ShowBoard()
{
  int n = 0;
  cout << "###################### 1.打印日志任务     ######################" << endl; 
  cout << "###################### 2.输入数据库任务   ######################" << endl; 
  cout << "###################### 3.执行网络请求任务 ######################" << endl;
  cout << "###################### 4.退出             ######################" << endl; 
  cout << "请输入你的选项" << endl;
  cin >> n;
  return n;
}

void CtrlProcess(const vector<EndPoint>& Process)
{
  int cnt = 0;
  while(true)
  {
    int command = ShowBoard();//交互式版本，即可以进行输入来控制。自动化版本，即通过随机(rand())的方式，发生任务
    if(command <= 0 || command >= 5) continue;
    if(command == 4) break;
    
    command -= 1;//下标从0开始
    cnt++;
    int course = cnt % 3;
    const string str = Process[course].GetName();
    cout << "进程: " << str << " | 执行任务" << command + 1 << endl;
    write(Process[course].write_fd,&command,sizeof(int));
    sleep(1);
  }
}

void CreatPrecess(vector<EndPoint>& Process)
{
  vector<int> fds;
  for(int i = 0; i < MAX; ++i)
  {
    int pipefd[2] = {0};
    int n = pipe(pipefd);
    assert(n != -1);
    (void)n;
    pid_t fd = fork();
    if(fd == 0)//子进程
    {
      for(auto& Fd : fds) close(Fd);//创建子进程会继承文件描述符，比如创建第三个子进程时，子进程会继承父进程的文件描述符，即标准输入、标准输出、标准错误、前两个子进程对应匿名管道的写端（须关闭）
      close(pipefd[1]);
      dup2(pipefd[0],0);
      waitCommant();
      close(pipefd[0]);
      exit(0);
    }
    close(pipefd[0]);
    Process.push_back(EndPoint(pipefd[1],fd));
    fds.push_back(pipefd[1]);
  }
}

void WaitProcess(vector<EndPoint>& Process)
{
  for(size_t i = 0; i < Process.size(); ++i)
  {
    //关闭管道文件，让子进程读到文件末尾，进而关闭子进程
    close(Process[i].write_fd);
    cout << "父进程要我退出 pid: " << Process[i].child_fd << endl;

    //回收子进程的僵尸状态
    int status = 0;
    waitpid(Process[i].child_fd,&status,0);
    cout << "父进程回收僵尸状态 " << Process[i].child_fd << endl;

    sleep(2);
  }
  sleep(5);
}

int main()
{
  vector<EndPoint> Process;

  CreatPrecess(Process);

  CtrlProcess(Process);

  WaitProcess(Process); 

  return 0;
}
